// -----------------------------------------------------------------------
//  <copyright file="ServiceExtensions.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2025 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2025/1/4 20:13</last-date>
// -----------------------------------------------------------------------

using System.Security.Claims;

using DaprPlus.Domain.Entity;
using DaprPlus.Logging;
using DaprPlus.Properties;
using DaprPlus.Settings;
using DaprPlus.Settings.Domain.Entities;
using DaprPlus.Settings.Domain.Services;

using Microsoft.Extensions.Caching.Distributed;


namespace DaprPlus.Extensions;

public static class ServiceExtensions
{
    /// <summary>
    /// 从启动模块加载DaprPlus模块服务信息
    /// </summary>
    public static IDaprPlusBuilder AddDaprPlus<TStartupModule>(this IServiceCollection services) where TStartupModule : ModuleBase
    {
        Check.NotNull(services, nameof(services));

        services.GetOrAddSingletonInstance(() => new StartupLogger());

        var builder = services.GetOrAddSingletonInstance<IDaprPlusBuilder>(() => new DaprPlusBuilder(services));

        builder.Build<TStartupModule>();
        return builder;
    }

    /// <summary>
    /// DaprPlus框架初始化，适用于非Web应用程序
    /// </summary>
    public static Task<IServiceProvider> UseDaprPlus(this IServiceProvider provider)
    {
        var build = provider.GetRequiredService<IDaprPlusBuilder>();
        return build.UseDaprPlus(provider);
    }

    /// <summary>
    /// 获取<see cref="IConfiguration"/>配置信息
    /// </summary>
    public static IConfiguration? GetConfiguration(this IServiceCollection services)
    {
        return services.GetSingletonInstanceOrNull<IConfiguration>();
    }

    /// <summary>
    /// 创建<see cref="IConfiguration"/>配置信息
    /// </summary>
    public static IConfiguration BuildConfiguration(this IServiceCollection services)
    {
        var configurationBuilder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory());
        if (File.Exists("appsettings.json"))
        {
            configurationBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
        }

        var envStr = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")?? "Production";

        if (File.Exists($"appsettings.{envStr}.json"))
        {
            configurationBuilder.AddJsonFile($"appsettings.{envStr}.json", optional: true, reloadOnChange: true);
        }
        var config = configurationBuilder.Build();
        return config;
    }

    /// <summary>
    /// 获取指定类型的配置信息
    /// </summary>
    /// <typeparam name="TOptions">选项类型</typeparam>
    /// <param name="services">注册服务集合</param>
    /// <param name="sectionName">配置路径</param>
    /// <returns></returns>
    public static TOptions GetOptions<TOptions>(this IServiceCollection services, string? sectionName = null)
        where TOptions : class, new()
    {
        var configuration = services.GetConfiguration();
        var options = new TOptions();
        if (configuration == null)
        {
            return options;
        }
        configuration.GetSection(sectionName ?? typeof(TOptions).Name).Bind(options);
        return options;
    }

    /// <summary>
    /// 使用指定配置节点配置指定选项类型
    /// </summary>
    /// <typeparam name="TOptions">选项类型</typeparam>
    /// <param name="services">注册服务集合</param>
    /// <param name="sectionName">配置节点路径</param>
    /// <returns></returns>
    public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string sectionName)
        where TOptions : class, new()
    {
        var configuration = services.GetConfiguration()!;
        services.Configure<TOptions>(configuration.GetSection(sectionName));

        // 监听配置变化，自动更新选项
        services.Configure<TOptions>(opts =>
        {
            configuration.GetSection(sectionName).Bind(opts);
        });

        return services;
    }

    /// <summary>
    /// 从服务提供者获取 <see cref="IUnitOfWork"/>
    /// </summary>
    /// <param name="provider">服务提供者</param>
    /// <param name="enableTransaction">是否启用事务</param>
    /// <returns></returns>
    public static IUnitOfWork GetUnitOfWork(this IServiceProvider provider, bool enableTransaction = false)
    {
        var unitOfWork = provider.GetRequiredService<IUnitOfWork>();
        if (enableTransaction)
        {
            unitOfWork.EnableTransaction();
        }

        return unitOfWork;
    }

    /// <summary>
    /// 获取指定实体类型的仓储对象
    /// </summary>
    public static IRepository<TEntity> GetRepository<TEntity>(this IServiceProvider provider)
        where TEntity : class, IEntity, IAggregateRoot
    {
        return provider.GetRequiredService<IRepository<TEntity>>();
    }

    /// <summary>
    /// 获取指定实体类型的查询仓储对象
    /// </summary>
    public static IQueryRepository<TEntity> GetQueryRepository<TEntity>(this IServiceProvider provider)
        where TEntity : class, IEntity
    {
        return provider.GetRequiredService<IQueryRepository<TEntity>>();
    }

    /// <summary>
    /// 获取分布式缓存对象
    /// </summary>
    public static IDistributedCache GetDistributedCache(this IServiceProvider provider)
    {
        return provider.GetRequiredService<IDistributedCache>();
    }

    /// <summary>
    /// 获取指定类型的设置信息
    /// </summary>
    public static async Task<TSetting> GetSettingAsync<TSetting>(this IServiceProvider provider, CancellationToken token = default)
        where TSetting : class, ISetting, new()
    {
        var settingStore = provider.GetRequiredService<ISettingStore>();
        var setting = await settingStore.GetSettingAsync<TSetting>(token);
        return setting;
    }

    /// <summary>
    /// 获取当前服务名称
    /// </summary>
    public static string GetServiceName(this IServiceProvider provider)
    {
        var context = provider.GetService<DaprPlusContext>() ?? throw new DaprPlusException(ResDaprPlus.String_Framework_Init_Not);
        return context.ServiceName;
    }

    /// <summary>
    /// 获取当前用户
    /// </summary>
    public static ClaimsPrincipal? GetCurrentUser(this IServiceProvider provider)
    {
        try
        {
            var user = provider.GetService<IPrincipal>();
            return user as ClaimsPrincipal;
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 从当前登录信息中获取用户名，再查询出用户信息
    /// </summary>
    public static async Task<TUser?> GetCurrentUserAsync<TUser>(this IServiceProvider provider, Func<string, ISpecification<TUser>> specFunc, CancellationToken token = default)
        where TUser : EntityBase, IAggregateRoot
    {
        var principal = provider.GetCurrentUser();
        if (principal?.Identity?.IsAuthenticated != true)
        {
            return null;
        }

        var userName = principal.Identity.Name!;
        var spec = specFunc(userName);
        var repository = provider.GetRepository<TUser>();
        var user = await repository.GetAsync(spec, token);
        return user;
    }

    /// <summary>
    /// 获取指定类型的设置选项
    /// </summary>
    public static T? GetOptions<T>(this IServiceProvider provider) where T : class
    {
        return provider.GetService<IOptionsMonitor<T>>()?.CurrentValue;
    }

    /// <summary>
    /// 如果指定服务不存在，创建实例并添加。
    /// 通常使用在依赖注入Build之前从IServiceCollection中获取注入单例对象
    /// </summary>
    public static TServiceType GetOrAddSingletonInstance<TServiceType>(this IServiceCollection services, Func<TServiceType> factory) where TServiceType : class
    {
        var item = services.GetSingletonInstanceOrNull<TServiceType>();
        if (item == null)
        {
            item = factory();
            services.AddSingleton<TServiceType>(item);
            services.ServiceLogDebug(typeof(TServiceType), item.GetType(), typeof(ServiceExtensions).FullName!);
        }
        return item;
    }

    /// <summary>
    /// 添加服务调试日志
    /// </summary>
    public static IServiceCollection ServiceLogDebug(this IServiceCollection services, ServiceDescriptor[] oldDescriptors, string logName)
    {
        var list = services.Except(oldDescriptors);
        foreach (var desc in list)
        {
            if (desc.IsKeyedService)
            {
                if (desc.KeyedImplementationType != null)
                {
                    var key = desc.ServiceKey?.ToString() ?? "null";
                    services.ServiceKeyedLogDebug(desc.ServiceType, desc.KeyedImplementationType, key, logName, desc.Lifetime);
                }
                continue;
            }

            if (desc.ImplementationType != null)
            {
                services.ServiceLogDebug(desc.ServiceType, desc.ImplementationType, logName, desc.Lifetime);
                continue;
            }

            if (desc.ImplementationInstance != null)
            {
                services.ServiceLogDebug(desc.ServiceType, desc.ImplementationInstance.GetType(), logName, desc.Lifetime);
            }
        }

        return services;
    }

    /// <summary>
    /// 添加服务调试日志
    /// </summary>
    public static IServiceCollection ServiceLogDebug<TServiceType, TImplementType>(this IServiceCollection services, string logName, ServiceLifetime lifetime = ServiceLifetime.Singleton)
    {
        Type serviceType = typeof(TServiceType), implementType = typeof(TImplementType);
        return services.ServiceLogDebug(serviceType, implementType, logName, lifetime);
    }

    /// <summary>
    /// 添加服务调试日志
    /// </summary>
    public static IServiceCollection ServiceLogDebug(this IServiceCollection services, Type serviceType, Type implementType, string logName, ServiceLifetime lifetime = ServiceLifetime.Singleton)
    {
        var lifetimeType = lifetime switch
        {
            ServiceLifetime.Singleton => ResDaprPlus.String_ServiceLifetime_Singleton,
            ServiceLifetime.Scoped => ResDaprPlus.String_ServiceLifetime_Scoped,
            _ => ResDaprPlus.String_ServiceLifetime_Transient
        };
        return services.LogDebug(ResDaprPlus.Format_Init_AddService_Debug.FormatWith(lifetimeType, serviceType.FullName,
            implementType.FullName), logName);
    }

    /// <summary>
    /// 添加启动调试日志
    /// </summary>
    public static IServiceCollection LogDebug(this IServiceCollection services, string message, string logName)
    {
        var logger = services.GetOrAddSingletonInstance(() => new StartupLogger());
        logger.LogDebug(message, logName);
        return services;
    }

    /// <summary>
    /// 添加服务调试日志
    /// </summary>
    public static IServiceCollection ServiceKeyedLogDebug<TServiceType, TImplementType>(this IServiceCollection services, string key, string logName, ServiceLifetime lifetime = ServiceLifetime.Singleton)
    {
        Type serviceType = typeof(TServiceType), implementType = typeof(TImplementType);
        return services.ServiceKeyedLogDebug(serviceType, implementType, key, logName, lifetime);
    }

    /// <summary>
    /// 添加服务调试日志
    /// </summary>
    public static IServiceCollection ServiceKeyedLogDebug(this IServiceCollection services, Type serviceType, Type implementType, string key, string logName, ServiceLifetime lifetime = ServiceLifetime.Singleton)
    {
        var lifetimeType = lifetime switch
        {
            ServiceLifetime.Singleton => ResDaprPlus.String_ServiceLifetime_Singleton,
            ServiceLifetime.Scoped => ResDaprPlus.String_ServiceLifetime_Scoped,
            _ => ResDaprPlus.String_ServiceLifetime_Transient
        };
        return services.LogDebug(ResDaprPlus.Format_Init_AddService_Debug_Key.FormatWith(lifetimeType,
            serviceType.FullName, implementType.FullName, key), logName);
    }

    /// <summary>
    /// 添加启动消息日志
    /// </summary>
    public static IServiceCollection LogInformation(this IServiceCollection services, string message, string logName)
    {
        var logger = services.GetOrAddSingletonInstance(() => new StartupLogger());
        logger.LogInformation(message, logName);
        return services;
    }
}
